package com.sc.nft.service.impl;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sc.nft.dao.*;
import com.sc.nft.entity.*;
import com.sc.nft.entity.vo.GetDaoByIdVO;
import com.sc.nft.entity.vo.PointsApplyExchangeRecordsDetailsVO;
import com.sc.nft.entity.vo.PointsApplyExchangeRecordsPageVO;
import com.sc.nft.enums.*;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.DaoEcologyPointsApplyExchangeRecordsService;
import com.sc.nft.service.DaoEcologyPointsWalletService;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.sup.Result;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Slf4j
@RequiredArgsConstructor
@Service
public class DaoEcologyPointsApplyExchangeRecordsServiceImpl implements DaoEcologyPointsApplyExchangeRecordsService {
    private final DaoEcologyPointsApplyExchangeRecordsDao daoEcologyPointsApplyExchangeRecordsDao;
    private final DaoEcologyPointsDao daoEcologyPointsDao;
    private final Redisson redisson;
    private final DigitalCollectionDao digitalCollectionDao;
    private final UserCreatorInfoDao userCreatorInfoDao;
    private final UserInfoDao userInfoDao;
    private final DaoEcologyPointsWalletService daoEcologyPointsWalletService;
    /**
     * 列表
     *
     * @param daoId
     * @param applyStatus
     * @param collectionId
     * @param startTime
     * @param endTime
     * @param mp
     * @return
     */
    @Override
    public IPage<PointsApplyExchangeRecordsPageVO> page(Long daoId, PointsExchangeCollectionStatusEnum applyStatus, Long collectionId, Date startTime, Date endTime, Page mp, PointsExchangeCollectionConsumeTypeEnum consumeType) {
        return daoEcologyPointsApplyExchangeRecordsDao.getPage(daoId,applyStatus,collectionId,startTime,endTime,mp,consumeType);
    }


    /**
     * 审核
     *
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result audit(Long id,String remark,PointsExchangeCollectionStatusEnum auditStatus) {
        DaoEcologyPointsApplyExchangeRecords applyExchangeRecords = daoEcologyPointsApplyExchangeRecordsDao.getById(id);
        Assert.notNull(applyExchangeRecords,()-> new GlobalRunTimeException("数据不存在"));
        Assert.isTrue(PointsExchangeCollectionStatusEnum.AUDITING.equals(applyExchangeRecords.getApplyStatus()),()-> new GlobalRunTimeException("非审核中无法操作"));
        switch (auditStatus) {
            case PASS:
                Assert.isTrue(daoEcologyPointsApplyExchangeRecordsDao.updateStatus(applyExchangeRecords.getId(),PointsExchangeCollectionStatusEnum.PASS,""),()-> new GlobalRunTimeException("操作失败"));
                break;
            case REFUSE:
                //涉及到燃料修改需要加锁
                RLock lock = redisson.getLock(RedisKeyEnum.TRANSFER_MARKET_VALUE_ACCOUNT_LOCK.getKey() + applyExchangeRecords.getDaoId());
                try {
                    boolean res = lock.tryLock(10, TimeUnit.SECONDS);
                    if (res) {
                        DaoEcologyPoints oldDaoEcologyPoints = daoEcologyPointsDao.getByDaoId(applyExchangeRecords.getDaoId());
                        Assert.isTrue(daoEcologyPointsApplyExchangeRecordsDao.updateStatus(applyExchangeRecords.getId(), PointsExchangeCollectionStatusEnum.REFUSE,remark == null ? "" : remark),()-> new GlobalRunTimeException("操作失败"));
                        if (applyExchangeRecords.getConsumeType() == PointsExchangeCollectionConsumeTypeEnum.POINTS) {
                            Assert.isTrue(daoEcologyPointsDao.addAmount(applyExchangeRecords.getDaoId(), applyExchangeRecords.getAmount()),()->new GlobalRunTimeException("恢复可用燃料失败"));
                            insertDetail(applyExchangeRecords, oldDaoEcologyPoints,applyExchangeRecords.getCollectionId());
                        }else {
                            Assert.isTrue(
                                    daoEcologyPointsWalletService.adjustAmount(applyExchangeRecords.getDaoId(),applyExchangeRecords.getLinkId(),applyExchangeRecords.getLinkName(),applyExchangeRecords.getAmount(), DaoEcologyPointsWalletLogTypeEnum.POINT_EXCHANGE_NFT_RETURNED, remark == null ? "" : remark)
                                    ,()->new GlobalRunTimeException("恢复可用积分失败"));
                        }

                    }else {
                        return Result.fail(ErrorCode.LATER_TRY);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    return Result.fail("系统繁忙,请稍后重试!");
                } finally {
                    lock.unlock();
                }
                break;
            case REVOKED:
                DaoEcologyPoints oldDaoEcologyPoints = daoEcologyPointsDao.getByDaoId(applyExchangeRecords.getDaoId());
                Assert.isTrue(daoEcologyPointsApplyExchangeRecordsDao.updateStatus(applyExchangeRecords.getId(), PointsExchangeCollectionStatusEnum.REVOKED,""),()-> new GlobalRunTimeException("操作失败"));
                if (applyExchangeRecords.getConsumeType() == PointsExchangeCollectionConsumeTypeEnum.POINTS) {
                    Assert.isTrue(daoEcologyPointsDao.addAmount(applyExchangeRecords.getDaoId(), applyExchangeRecords.getAmount()),()->new GlobalRunTimeException("恢复可用燃料失败"));
                    insertDetail(applyExchangeRecords, oldDaoEcologyPoints,applyExchangeRecords.getCollectionId());
                }else {
                    Assert.isTrue(
                            daoEcologyPointsWalletService.adjustAmount(applyExchangeRecords.getDaoId(),applyExchangeRecords.getLinkId(),applyExchangeRecords.getLinkName(),applyExchangeRecords.getAmount(), DaoEcologyPointsWalletLogTypeEnum.POINT_EXCHANGE_NFT_RETURNED, remark == null ? "" : remark)
                            ,()->new GlobalRunTimeException("恢复可用积分失败"));
                }
                break;
        }
        return Result.success();
    }

    private void insertDetail(DaoEcologyPointsApplyExchangeRecords applyExchangeRecords, DaoEcologyPoints oldDaoEcologyPoints,Long collectionId) {
        DigitalCollection collection = digitalCollectionDao.getById(collectionId);
        DaoEcologyPointsDetail amountDetail = new DaoEcologyPointsDetail();
        amountDetail.setDaoId(applyExchangeRecords.getDaoId());
        amountDetail.setAmountType(DaoEcologyPointsDetailAmountTypeEnum.AVAILABLE);
        amountDetail.setType(DaoEcologyPointsDetailRecordsTypeEnum.POINT_EXCHANGE_NFT_RETURNED);
        amountDetail.setAmount(applyExchangeRecords.getAmount());
        amountDetail.setRealAmount(applyExchangeRecords.getAmount());
        amountDetail.setBeforeBalance(oldDaoEcologyPoints.getAmount());
        amountDetail.setAfterBalance(oldDaoEcologyPoints.getAmount().add(applyExchangeRecords.getAmount()));
        amountDetail.setIsAdd(Boolean.TRUE);
        amountDetail.setRemark("兑换【"+collection.getFirstTitle()+"】");
        amountDetail.insert();
    }


    /**
     * 审核详情
     *
     * @param id
     * @return
     */
    @Override
    public PointsApplyExchangeRecordsDetailsVO details(Long id) {
        DaoEcologyPointsApplyExchangeRecords applyExchangeRecords = daoEcologyPointsApplyExchangeRecordsDao.getById(id);
        Assert.notNull(applyExchangeRecords,()-> new GlobalRunTimeException("数据不存在"));
        PointsApplyExchangeRecordsDetailsVO detailsVO = new PointsApplyExchangeRecordsDetailsVO();
        if (applyExchangeRecords.getConsumeType() == PointsExchangeCollectionConsumeTypeEnum.POINTS) {
            DaoEcologyPoints ecologyPoints = daoEcologyPointsDao.getByDaoId(applyExchangeRecords.getDaoId());
            detailsVO.setAvailablePoints(ecologyPoints == null ? BigDecimal.ZERO : ecologyPoints.getAmount());
        }else {
            DaoEcologyPointsWallet daoEcologyPointsWallet = daoEcologyPointsWalletService.getByDaoIdAndPointsId(applyExchangeRecords.getDaoId(), applyExchangeRecords.getLinkId());
            detailsVO.setAvailablePoints(daoEcologyPointsWallet == null ? BigDecimal.ZERO : daoEcologyPointsWallet.getAmount());
        }
        DigitalCollection collection = digitalCollectionDao.getById(applyExchangeRecords.getCollectionId());
        GetDaoByIdVO dao = userCreatorInfoDao.getDaoById(applyExchangeRecords.getDaoId());
        UserInfo userInfo = userInfoDao.getById(applyExchangeRecords.getToUserId());
        detailsVO.setId(applyExchangeRecords.getId());
        detailsVO.setApplyNum(applyExchangeRecords.getApplyNum());
        detailsVO.setDaoName(dao == null ? "" : dao.getDaoName());
        detailsVO.setAmount(applyExchangeRecords.getAmount());
        detailsVO.setCollectionName(collection == null ? "" : collection.getFirstTitle());
        detailsVO.setToUserAccount(userInfo == null ? "" : userInfo.getUserTel());
        detailsVO.setLinkName(applyExchangeRecords.getLinkName());
        return detailsVO;
    }
}
